/**
 * 深拷贝函数
 *
 * @param sourceData 要深拷贝的数据
 * @param hash 用于记录已拷贝对象，避免循环引用
 * @returns 深拷贝后的数据
 */
export function deepClone<T>(sourceData: T, hash = new WeakMap()): T {
  if (sourceData === null || typeof sourceData !== 'object') {
    return sourceData
  }

  if (hash.has(sourceData)) {
    return hash.get(sourceData)
  }

  if (sourceData instanceof Date) {
    return new Date(sourceData) as unknown as T
  }

  if (sourceData instanceof RegExp) {
    return new RegExp(sourceData) as unknown as T
  }

  if (Array.isArray(sourceData)) {
    const cloneArr = [] as unknown as T
    hash.set(sourceData, cloneArr)
    sourceData.forEach((item, i) => {
      (cloneArr as unknown as any[])[i] = deepClone(item, hash)
    })
    return cloneArr
  }

  if (sourceData instanceof Map) {
    const cloneMap = new Map()
    hash.set(sourceData, cloneMap)
    sourceData.forEach((value, key) => {
      cloneMap.set(key, deepClone(value, hash))
    })
    return cloneMap as unknown as T
  }

  if (sourceData instanceof Set) {
    const cloneSet = new Set()
    hash.set(sourceData, cloneSet)
    sourceData.forEach((value) => {
      cloneSet.add(deepClone(value, hash))
    })
    return cloneSet as unknown as T
  }

  const cloneObj = Object.create(Object.getPrototypeOf(sourceData))
  hash.set(sourceData, cloneObj)
  for (const key in sourceData) {
    if (Reflect.has(sourceData, key)) {
      cloneObj[key] = deepClone(sourceData[key], hash)
    }
  }
  return cloneObj
}
